from .agent import *

class Advantage:
    Superior, Indifferent, Inferior = range(3)

class EventType:
    (
        ForceToSuperior,
        ForceToInferior,
        ScoreToSuperior,
        ScoreToNonsuperior,
        ObtainCity,
        LostCity,
        CityAllOurs,
        InitialSituation
    ) = range(8)

class MissionState:
    (
        Attack,
        Defense,
    ) = range(2)

#状态父类
class State(object):
    def exec(self, *arg):
        pass

    def exit(self, *arg):
        pass

    def state_judgement(self, *arg):
        pass

class AttackState(State):
    #进入 进攻状态
    def exec(self, mission, agent):
        # 进攻点位推理 优先进攻分值大的夺控点
        # TODO：目前想定中主夺控点排列在前 所以直接遍历夺控点
        for i in agent.observation['cities']:
            if i['flag'] != agent.color:
                mission.parameter = i
                break
        mission.attack(agent)
    #退出状态
    def exit(self, mission, agent):
        pass
    #事件判断
    def state_judgement(self, events, agent):
        event = events.event_list.pop()
        if event == EventType.ForceToSuperior:
            return MissionState.Attack
        elif event == EventType.ForceToInferior:
            return MissionState.Defense
        elif event == EventType.ObtainCity:
            if events.score_advantage == Advantage.Superior:
                for i in agent.observation['cities']:
                    if i['flag'] != agent.color:
                        return MissionState.Defense
                return MissionState.Attack
            else:
                for i in agent.observation['cities']:
                    if i['flag'] != agent.color:
                        return MissionState.Attack
        elif event == EventType.ScoreToNonsuperior:
            return MissionState.Attack
        elif event == EventType.ScoreToSuperior:
            for i in agent.observation['cities']:
                if i['flag'] == -1:
                    return MissionState.Attack
            return MissionState.Defense
        elif event == EventType.ObtainCity:
            return MissionState.Defense
        elif event == EventType.LostCity:
            if events.score_advantage == Advantage.Superior:
                return MissionState.Defense
            else:
                return MissionState.Attack
        elif event == EventType.InitialSituation:
            return MissionState.Attack
        else:
            print('错误，出现意料外的情况')
            return MissionState.Attack
            #
            # for i in agent.observation['cities']:
            #     if i['flag'] == -1:
class DefenseState(State):
    #进入 防御状态
    def exec(self, mission, agent):
        mission.defense(agent)
    #退出状态
    def exit(self, mission, agent):
        pass
    #事件判断
    def state_judgement(self, events, agent):
        event = events.event_list.pop()
        if event == EventType.ForceToSuperior:
            for i in agent.observation['cities']:
                if i['flag'] != agent.color:
                    return MissionState.Attack
            return MissionState.Defense
        elif event == EventType.ForceToInferior:
            return MissionState.Defense
        elif event == EventType.ScoreToSuperior:
            for i in agent.observation['cities']:
                if i['flag'] != agent.color:
                    return MissionState.Attack
            return MissionState.Defense
        elif event == EventType.ScoreToNonsuperior:
            for i in agent.observation['cities']:
                if i['flag'] != agent.color:
                    return MissionState.Attack
            return MissionState.Defense
        elif event == EventType.LostCity:
            if events.score_advantage == Advantage.Superior:
                return MissionState.Defense
            else:
                return MissionState.Defense
        else:
            print('错误，出现意料外的情况')
            return MissionState.Attack

class WholeMissionSchedule:
    def __init__(self, agent):
        self.mission = MissionState.Attack
        self.mission_flag = False
        self.events = Event(agent)
        self.states = {MissionState.Attack: AttackState(), MissionState.Defense: DefenseState()}
        self.parameter = None
        # TODO:测试用属性 用于显示当前状态
        self.state_list = [MissionState.Attack,MissionState.Defense]

    def update(self, agent):
        # 事件判断
        self.events.orient(agent)
        # 状态转换 确定参数
        self.update_state(agent,self.events,self.mission)

    #   通过给定的state返回其对应的状态对象
    def getFsm(self, state):
        return self.states[state]

    #   切换对象的状态
    def update_state(self, agent, events, mission):
        if len(events.event_list) != 0:
            print(f'相应事件：{self.events.event_list}')
            state = self.getFsm(mission)
            new_mission = state.state_judgement(events, agent)
            if new_mission is not None:
                if new_mission == mission:
                    #   保持原状态
                    fs = self.getFsm(mission)
                    fs.exec(self, agent)
                else:
                    #   先退出旧状态
                    old_fsm = self.getFsm(mission)
                    old_fsm.exit(self, agent)
                    #   执行新状态
                    new_fsm = self.getFsm(new_mission)
                    new_fsm.exec(self, agent)
                self.mission_flag = True
            else:
                self.mission_flag = False
            # print(f'当前状态：{self.state_list[self.mission]}')
        else:
            self.mission_flag = False

    def attack(self,agent):
        self.mission = MissionState.Attack

    def defense(self,agent):
        self.mission = MissionState.Defense


    def full_attack(self,agent):
        self.mission = MissionState.FullAttack


    def full_defense(self,agent):
        self.mission = MissionState.FullDefense



class Event:
    def __init__(self,agent):
        self.last_force_advantage = Advantage.Indifferent
        self.last_score_advantage = Advantage.Indifferent
        self.last_cities_state = None
        self.force_advantage = None
        self.score_advantage = None
        self.cities_state = None
        self.event_list = []


    def orient(self,agent):
        #计算兵力变化
        self.confirm_force_advantage(agent)
        #计算分数变化
        self.confirm_score_advantage(agent)
        #判断夺控点变化情况
        self.cities_state = agent.observation['cities']
        #计算事件
        self.generate_event(agent)

    def confirm_force_advantage(self,agent):
        #计算self.force_advantage
        our_operator_weight = 0
        enemy_operator_weight = 0
        for obj_id, valid_actions in agent.observation["valid_actions"].items():
            bop=agent.get_bop(obj_id)
            if bop['sub_type'] == 0:
                our_operator_weight += 10*bop['blood']
            elif bop['sub_type'] == 1:
                our_operator_weight += 4*bop['blood']
            elif bop['sub_type'] == 4:
                our_operator_weight += 1*bop['blood']
        #计算敌方算子权重
        for obj_id, bop in agent.situation.enemy.items():
            if bop['color'] != agent.color:
                if bop['sub_type'] == 0:
                    enemy_operator_weight += 10*bop["cur_blood"]
                elif bop['sub_type'] == 1:
                    enemy_operator_weight += 4*bop["cur_blood"]
                elif bop['sub_type'] == 4:
                    enemy_operator_weight += 1*bop["cur_blood"]
        # 这个计算方式感觉不是很好，可能会出现开局双方算子并不平衡的情况
        if our_operator_weight > enemy_operator_weight*2:
            self.force_advantage = Advantage.Superior
        elif our_operator_weight*2 < enemy_operator_weight:
            self.force_advantage = Advantage.Inferior
        else:
            self.force_advantage = Advantage.Indifferent

    def confirm_score_advantage(self,agent):
        #计算self.score_advantage
        # 双方开局分数根据算子情况并不相等
        if agent.color == 0:#如果是红方
            if agent.observation['scores']['red_win'] > agent.observation['scores']['red_remain']/2:
                self.score_advantage = Advantage.Superior
            else:
                self.score_advantage = Advantage.Indifferent
        elif agent.color == 1:#如果是蓝方
            if agent.observation['scores']['blue_win'] > agent.observation['scores']['blue_remain']/2:
                self.score_advantage = Advantage.Superior
            else:
                self.score_advantage = Advantage.Indifferent

    def generate_event(self,agent):
        if self.force_advantage != self.last_force_advantage:
            if self.force_advantage == Advantage.Superior and self.last_force_advantage == Advantage.Indifferent:
                self.event_list.append(EventType.ForceToSuperior)
            elif self.force_advantage == Advantage.Inferior and self.last_force_advantage == Advantage.Indifferent:
                self.event_list.append(EventType.ForceToInferior)
            self.last_force_advantage = self.force_advantage
            self.last_score_advantage = self.score_advantage
            self.last_cities_state = self.cities_state
        elif self.score_advantage != self.last_score_advantage:
            if self.score_advantage == Advantage.Superior and self.last_score_advantage != Advantage.Superior:
                self.event_list.append(EventType.ScoreToSuperior)
            elif self.score_advantage != Advantage.Superior and self.last_score_advantage == Advantage.Superior:
                self.event_list.append(EventType.ScoreToNonsuperior)
            self.last_force_advantage = self.force_advantage
            self.last_score_advantage = self.score_advantage
            self.last_cities_state = self.cities_state
        else:
            if self.last_cities_state:
                for x in range(len(self.cities_state)):
                    i = self.cities_state[x]
                    j = self.last_cities_state[x]
                    if i['flag'] != j['flag']:
                        if i['flag'] != agent.color and j['flag'] == agent.color:
                            self.event_list.append(EventType.LostCity)
                        elif i['flag'] == agent.color and j['flag'] != agent.color:
                            self.event_list.append(EventType.CityAllOurs)
                            for y in self.cities_state:# 如果占领了一个夺控点 判断是否占领全部夺控点
                                if y['flag'] != agent.color:
                                    self.event_list.pop()
                                    self.event_list.append(EventType.ObtainCity)
                                    break
                self.last_force_advantage = self.force_advantage
                self.last_score_advantage = self.score_advantage
                self.last_cities_state = self.cities_state
            else:
                self.last_force_advantage = self.force_advantage
                self.last_score_advantage = self.score_advantage
                self.last_cities_state = self.cities_state
                self.event_list.append(EventType.InitialSituation)